
#include "zen_game_node.h"
#include "zen_log.h"
#include "zen_game_activity.h"

namespace Zen
{
	namespace Game
	{

		/**
		 @ref zen_game_root.cpp
		 */

		void Node::ReleaseSelf()
		{
			/// remove self from parent.
			if (!mUpperNodeRef.expired())
			{
				auto p = mUpperNodeRef.lock();
				for (auto i = p->mInnerNodes.begin(); i != p->mInnerNodes.end(); ++i)
				{
					if (i->get() == this)
					{
						p->mInnerNodes.erase(i);
						break;
					}
				}
				mUpperNodeRef.reset();
			}
			this->StopAttachedActions();
			this->RemoveAttachedTouches();
			this->ReleaseInnerNodes();
		}

		void Node::StopAttachedActions()
		{
			Activity::Only()->GetActionDispather()->StopActionsOnNode(GetSharedFromThis<Node>());
		}

		void Node::RemoveAttachedTouches()
		{
			Activity::Only()->GetTouchDispatcher()->RemoveTouchHandleOnNode(GetSharedFromThis<Node>());
		}

		void Node::AddNode(std::shared_ptr<Node> node)
		{
			__zen_must_else(node, "add nullptr node");
			__zen_must_else(node->mUpperNodeRef.expired(), "node already has a parent");

			this->mInnerNodes.push_back(node);
			this->mIsInnerOrderDirty = true;
			node->mUpperNodeRef = GetSharedFromThis<Node>();
			node->OnLoad();
		}

		void Node::ReleaseInnerNodes()
		{
			for (auto i : mInnerNodes)
			{
				i->mUpperNodeRef.reset();
				i->ReleaseSelf();
			}
			mInnerNodes.clear();
		}

		void Node::SortInnerNodes()
		{
			if (!mIsInnerOrderDirty) return;

			auto comp = [](NodePtr a, NodePtr b) { return a->mSiblingOrder < b->mSiblingOrder; };
			std::stable_sort(mInnerNodes.begin(), mInnerNodes.end(), comp);
			mIsInnerOrderDirty = false;
		}

		auto Node::GetInnerNodes() -> std::vector<NodePtr>
		{
			return mInnerNodes;
		}

		std::shared_ptr<Node> Node::GetUpperNode()
		{
			return mUpperNodeRef.lock();
		}

		void Node::SetVisible(bool v)
		{
			mIsVisible = v;
		}

		bool Node::IsVisible() const
		{
			return mIsVisible;
		}

		void Node::SetEnabled(bool v)
		{
			mIsEnabled = v;
		}

		bool Node::IsEnabled() const
		{
			return mIsEnabled;
		}

		void Node::SetSiblingOrder(int index)
		{
			if (mSiblingOrder == index) return;
			mSiblingOrder = index;
			auto upper = GetUpperNode();
			if (upper) upper->mIsInnerOrderDirty = true;
		}

		int Node::GetSiblingOrder() const
		{
			return mSiblingOrder;
		}

		void NodeWithColor::SetColor(Color4f const& color)
		{
			mColor = color;
			mIsColorDirty = true;
		}

		Color4f const& NodeWithColor::GetColor()
		{
			return mColor;
		}

		void NodeWithSampler::SetSampler(Zen::Graphics::SamplerMode mode)
		{
			mSampler = mode;
			mIsSamplerDirty = true;
		}

		Zen::Graphics::SamplerMode const& NodeWithSampler::GetSampler() const
		{
			return mSampler;
		}
	} // namespace Game
} // namespace Zen
